package net.oschina.arvin.multi.field.sort;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

/**
 * @author Arvin
 * @time 2017/10/1 21:54
 */
public class MultiFieldSortComparator implements Comparator<Object> {

    private final List<SortItem> sortItemList;

    public MultiFieldSortComparator(List<SortItem> sortItemList) {
        this.sortItemList = sortItemList;
    }

    /**
     * @param sorts    排序配置，使用 ',' 号分割每一个属性排序字段配置， 格式为 field1:asc,field2:desc......
     * @param dataType 数据类型
     */
    public MultiFieldSortComparator(String sorts, Class<?> dataType) {
        if (null == sorts || "".equals(sorts.trim())) {
            this.sortItemList = null;
        } else {
            this.sortItemList = new ArrayList<SortItem>();
            String[] sortItemConfigArr = sorts.trim().split(",");
            if (sortItemConfigArr.length > 0) {
                for (String sortItemConfig : sortItemConfigArr) {
                    if (null != sortItemConfig && !"".equals(sortItemConfig.trim())) {
                        String[] arr = sortItemConfig.trim().split(":");
                        if (arr.length > 0) {
                            String field = arr[0];
                            if (null != field && !"".equals(field.trim())) {
                                String ascStr = arr.length > 1 ? arr[1] : "asc";
                                ascStr = ascStr == null || "".equals(ascStr.trim()) ? "asc" : ascStr;
                                boolean isAsc = ascStr.equalsIgnoreCase("asc");
                                if (Map.class.isAssignableFrom(dataType)) {
                                    this.sortItemList.add(new MapSortItem(field, isAsc));
                                } else {
                                    try {
                                        Field sortField = dataType.getDeclaredField(field);
                                        sortField.setAccessible(true);
                                        this.sortItemList.add(new ModelSortItem(sortField, isAsc));
                                    } catch (NoSuchFieldException ignored) {
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    public List<SortItem> getSortItemList() {
        return sortItemList;
    }

    @Override
    public int compare(Object v1, Object v2) {
        if (v1 == null && v2 == null) {
            return 0;
        } else if (v1 != null && v2 == null) {
            return 1;
        } else if (v1 == null) {
            return -1;
        } else {
            return multiFieldCompare(v1, v2);
        }
    }

    @SuppressWarnings({"unchecked"})
    private int multiFieldCompare(Object v1, Object v2) {
        assert v1 != null;
        assert v2 != null;
        if (this.sortItemList.isEmpty()) {
            if (v1.getClass() == v2.getClass() && Comparable.class.isAssignableFrom(v1.getClass())) {
                return ((Comparable) v1).compareTo(v1);
            }
        } else {
            for (SortItem sortItem : sortItemList) {
                int ret = sortItem.compare(v1, v2);
                if (ret != 0) {
                    return ret;
                }
            }
        }
        return 0;
    }
}
